// @ts-nocheck
import { isBrowser } from '@/uni_modules/lime-shared/isBrowser'
import { sleep } from '@/uni_modules/lime-shared/sleep'
import { isString } from '@/uni_modules/lime-shared/isString'
import { isPromise } from '@/uni_modules/lime-shared/isPromise'
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
import { fileToDataURL, dataURItoBlob } from './utils'
import type {IShrinkOptions, IShrinkImageOptions, IOffscreenCanvas, IFileTyep} from './type'

export class Shrink {
	options : IShrinkOptions = {
		quality: 80,
		success: () => { },
		error: () => { },
	};
	constructor(options : IShrinkOptions = {}) {
		for (let key in options) {
			this[key] = options[key]
		}
	}
	getImageOrientation(img: string){
		let orientation = 1;
		return Promise.resolve(orientation)
	}
	dataToFile(data: any, name: string, type: string) {
		return new File([data], name, {
			type,
		});
	}
	dataURLToImage(dataURL : string, canvas ?: any) : Promise<HTMLImageElement> {
		return new Promise((resolve) => {
			const img = this.createImage(canvas);
			img.onload = () => resolve(img);
			img.src = dataURL;
		});
	}
	createImage(canvas ?: IOffscreenCanvas) {
		if (isBrowser) {
			return new Image()
		} else if (canvas && canvas.createImage) {
			return canvas.createImage()
		}
	}
	createCanvas() {
		if (isBrowser) {
			return document.createElement('canvas')
		} else if (typeof uni !== 'undefined' && uni.createOffscreenCanvas) {
			return uni.createOffscreenCanvas({ type: '2d' }) as HTMLCanvasElement
		}
	}
	canvastoFile(canvas : any, type : string, quality : number) {
		type = type.replace('pg', 'peg');
		if (isBrowser && canvas.toBlob) {
			return new Promise((resolve) =>
				canvas.toBlob((blob) => resolve(blob), type, quality)
			);
		}
		const res = canvas.toDataURL(type, quality)
		if (isPromise(res)) {
			return res
		} else {
			return Promise.resolve(res)
		}
	}
	async compress(file : IFileTyep, options : IShrinkImageOptions = this.options) : Promise<(IFileTyep)> {
		const { quality } = options
		try {
			const canvas = this.createCanvas();
			const context = canvas.getContext("2d");
			const url = isString(file) ? file : file['path']

			const type : string = !isString(file) && file.type ? file.type : `image/${/\.([0-9a-z]+)(?:[\?#]|$)/i.exec(url)?.[1] || 'jpeg'}`;
			const name : string = !isString(file) && file.name ? file.name : /\/?([^\/?#]+)\.[^\.\/?#]+(#|\?|$)/g.exec(url)?.[1] || `${+new Date()}`;
			let base64 : string = ''
			if (isBrowser && !isString(file)) {
				base64 = await fileToDataURL(file);
			} else {
				base64 = url
			}
			const img = await this.dataURLToImage(base64, canvas);
			const { width, height } = img
			canvas.width = width;
			canvas.height = height;
			await sleep()
			// 调整坐标系
			context.setTransform(1, 0, 0, 1, 0, 0);
			context.clearRect(0, 0, width, height);
			
			const orientation = await this.getImageOrientation(base64);
			// 根据图片方向进行旋转，并在 Canvas 上绘制
			if(orientation > 4) {
				canvas.width = height;
				canvas.height = width;
				await sleep()
			}
			const orientations = {
				2: [-1, 0, 0, 1, width, 0],
				3: [-1, 0, 0, -1, width, height],
				4: [1, 0, 0, -1, 0, height],
				5: [0, 1, 1, 0, 0, 0],
				6: [0, 1, -1, 0, height, 0],
				7: [0, -1, -1, 0, height, width],
				8: [0, -1, 1, 0, 0, width],
			}
			const transform = orientations[orientation]
			if(transform) {
				context.transform(...transform);
			}
			context.drawImage(img, 0, 0, width, height);
			if ('draw' in context) {
				const draw = () => new Promise(resolve => context['draw'](false, resolve))
				await draw()
				await sleep()
			}
			
			let res = await this.canvastoFile(canvas, type, quality / 100)
			if(isBrowser && isBase64(res)) {
				res = dataURItoBlob(res)
			}
			return this.dataToFile(res, name, type)
			
		} catch (error) {
			throw new Error(error.message);
		}
	}
	compressImage(file : IFileTyep | IFileTyep[], options : IShrinkImageOptions = this.options) {
		if (!file) throw new Error("file can not be null");
		if (Array.isArray(file)) {
			return Promise.all(file.map((file) => this.compress(file, options)))
		} else {
			return this.compress(file, options)
		}
	}
}

export function shrinkImage(file : IFileTyep | IFileTyep[], options : IShrinkImageOptions) {
	const shrink = new Shrink()
	return shrink.compressImage(file, options)
}